package com.lsp.microorder.pay.service.impl;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.domain.AlipayTradeCloseModel;
import com.alipay.api.domain.AlipayTradeQueryModel;
import com.alipay.api.domain.AlipayTradeWapPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeCloseRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.alipay.api.response.AlipayTradeCloseResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeWapPayResponse;
import com.lsp.microcommon.exception.CommonException;
import com.lsp.microorder.pay.config.AliPayProperties;
import com.lsp.microorder.pay.param.PayParam;
import com.lsp.microorder.pay.param.PayResultParam;
import com.lsp.microorder.pay.service.PayService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.function.Consumer;

@Slf4j
@Service
public class AliPayServiceImpl implements PayService {

    @Resource
    private AlipayClient alipayClient;

    @Resource
    private AliPayProperties aliPayProperties;


//    @Resource
//    private WebSocket webSocket;

    /**
     * 后端服务端向支付宝系统发送请求，获取二维码链接
     *
     * @param
     * @return
     */
    @Override
    public String createPayOrder(PayParam appPayParams) {

        log.info("开始调用支付宝支付接口");
        // 使用的支付方式不同，请求对象和Model也都不同
        AlipayTradeWapPayRequest alipay_request = new AlipayTradeWapPayRequest();
        // 封装请求支付信息
        AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
        // 设置支付产品的编码
        model.setProductCode("QUICK_WAP_WAY");
        //订单编号，不可重复
        model.setOutTradeNo(appPayParams.getTradeNo());
        //订单名称,拼接用户编码
        model.setSubject(appPayParams.getSubject());
        //订单金额
        model.setTotalAmount(appPayParams.getTotalAmount().setScale(2, BigDecimal.ROUND_HALF_UP).toString());
        // 设置中途退出的跳转路径
        model.setQuitUrl(aliPayProperties.getQuitUrl());
        alipay_request.setBizModel(model);
        // 异步通知地址
        // 为什么后面要拼接orderId呢？
//            支付宝支付和微信支付的一个不同点在于，支付宝支付可与获取到路径拼接的参数，而微信支付不能获取到路径中拼接的参数
//            因此这个判断一句可以作为支付宝支付和微信支付的判断条件
        alipay_request.setNotifyUrl(aliPayProperties.getNotifyUrl() + "?orderNo=" + appPayParams.getTradeNo());
        // 支付成功后跳转的地址
        alipay_request.setReturnUrl(aliPayProperties.getReturnUrl());

        // 执行支付的返回值
        String result = "";
        try {
            // 调用SDK生成订单
            AlipayTradeWapPayResponse response = alipayClient.pageExecute(alipay_request);
            result = response.getBody();
            log.info("调用支付宝支付接口返回值result:" + result);
            // 返回form表单的字符串
            return result;
        } catch (AlipayApiException e) {
            throw new RuntimeException("支付宝支付失败");
        }
    }

    @Override
    public void notify(HttpServletRequest request, HttpServletResponse response, Consumer<PayResultParam> consumer) {
        log.info("进入支付宝异步回调方法");
        Map<String, String> map = new HashMap<>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = iter.next();
            String[] values = requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            map.put(name, valueStr);
        }
//        针对支付宝，回调路径中增加的参数进行验签时，会失败，所以需要手动删除
        map.remove("orderNo");
        //获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表
        //支付宝交易号
        String tradeNo = request.getParameter("trade_no");
        //获取总金额
        String totalFee = request.getParameter("total_amount");
        //获取订单号
        String orderNo = request.getParameter("out_trade_no");
        //获取交易状态
        String tradeStatus = request.getParameter("trade_status");
        log.info("支付宝异步回调交易状态trade_status：" + tradeStatus);

        //验证签名
        boolean signVerified = false;
        try {
            signVerified = AlipaySignature.rsaCheckV1(map,
                    aliPayProperties.getAlipayPublicKey(),
                    aliPayProperties.getCharset(),
                    aliPayProperties.getSignType());
            log.info("支付宝异步回调方法：验签结果" + signVerified);
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return;
        }
        if (signVerified) {
            try {
                if ("TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISH".equals(tradeStatus)) {
                    BigDecimal totalFees = new BigDecimal(totalFee);
                    // 支付后业务处理
//                    写针对订单的自定义操作，例如修改订单状态为已付款
                    PayResultParam param = new PayResultParam();
                    param.setOrderNo(orderNo);
                    param.setPayTradeNo(tradeNo);
//                    通过函数式接口
                    consumer.accept(param);
                } else {
                    return;
                }
                log.info("支付成功异步回调success");
                // 向前端发送一条支付成功的通知
//                webSocket.sendMessage("true");
                //该语句不要修改或删除
//                如果没问题的话返回给支付宝success
//                如果有问题返回fail，过一段时间支付宝重新回调
                response.getOutputStream().println("success");
                response.getOutputStream().close();
            } catch (Exception e) {
                log.info("支付成功异步回调异常:" + e.getMessage());
            }
        } else {
            log.info("支付成功异步回调fail");
//            webSocket.sendMessage("false");
            try {
                response.getOutputStream().println("fail");
                response.getOutputStream().close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return;
    }

    @Override
    public String payStates(String orderNo) {
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        AlipayTradeQueryModel model = new AlipayTradeQueryModel();
        model.setOutTradeNo(orderNo);
        request.setBizModel(model);
        AlipayTradeQueryResponse response = null;
        try {
            response = alipayClient.execute(request);
            System.out.println(response.getBody());
//            获取到支付订单id
            String outTradeNo = response.getOutTradeNo();
            if (response.isSuccess()) {
                System.out.println("调用成功");
                String tradeStatus = response.getTradeStatus();// WAIT_BUYER_PAY
                if (tradeStatus.equals("WAIT_BUYER_PAY")) {
                    throw new RuntimeException("等待支付");// 还需要返回特定的异常编码
                }
                return outTradeNo;
            } else {
                throw new RuntimeException("调用异常");
            }

        } catch (AlipayApiException e) {
            e.printStackTrace();
            throw new RuntimeException("查询支付状态异常");
        }
    }

    @Override
    public void closePay(String orderNo) {
        AlipayTradeCloseRequest request = new AlipayTradeCloseRequest();
        AlipayTradeCloseModel model = new AlipayTradeCloseModel();
        model.setOutTradeNo(orderNo); // 商户订单号
        request.setBizModel(model);
        AlipayTradeCloseResponse response = null;
        try {
            response = alipayClient.execute(request);
            System.out.println(response.getBody());
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void returnNotify(HttpServletRequest request, HttpServletResponse response) {

        log.info("支付宝同步回调方法");
        Map<String, String> map = new HashMap<>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = iter.next();
            String[] values = requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            map.put(name, valueStr);
        }
        String a = "3";
        try {
            a.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表(以下仅供参考)//
//        String trade_no = request.getParameter("trade_no");             //支付宝交易号
//        String order_no = request.getParameter("out_trade_no");         //获取订单号
//        String total_fee = request.getParameter("total_amount");           //获取总金额
//		String userId = feignAlipayService.getUserById(order_no);
        //验证签名
        boolean signVerified = false;
        try {
            signVerified = AlipaySignature.rsaCheckV1(map,
                    aliPayProperties.getAlipayPublicKey(),
                    aliPayProperties.getCharset(),
                    aliPayProperties.getSignType());
            log.info("支付宝同步回调方法:验签成功");
        } catch (com.alipay.api.AlipayApiException e) {
            e.printStackTrace();
            throw new RuntimeException("验签失败");
        }
        // 如果验证通过
        if (signVerified) {
            // 修改相关数据
            log.info("支付宝同步调用支付成功");

        } else {
            log.info("支付宝支付异常");
            throw new CommonException("支付宝支付异常");
        }
    }

    public static void addPay(String tradeNo, Consumer<String> consumer) {
        consumer.accept(tradeNo);
    }
}
